#include "internal.h"

uint8_t nfc_conf[CONF_LEN] = { 0x90, 0x04, 0xFF, 0XFF, 0xFF, 0xFF, 0XFF,
			       0xFF, 0xFF, 0XFF, 0xFF, 0xFF, 0XFF, 0xFF };
uint8_t nfc_id[ID_LEN] = { 0 };
uint8_t nfc_data[DATA_LEN] = { 0 };
uint8_t nfc_stat[STAT_LEN] = { 0 };

struct gatts_char chars[] = {
	// clang-format off
	/*    uuid		value		length		max_length	cccd	perm */	
[NFC_CONF] = {uuid16(0xFF01), 	nfc_conf, 	CONF_LEN, 	20, 		0x0000,	GATTS_PERM_READ|GATTS_PERM_WRITE,},
[NFC_ID]   = {uuid16(0xFF02), 	nfc_id, 	ID_LEN, 	20, 		0x0000,	GATTS_PERM_READ|GATTS_PERM_INDICATE,},
[NFC_DATA] = {uuid16(0xFF03), 	nfc_data, 	DATA_LEN, 	20, 		0x0000,	GATTS_PERM_READ,},
[NFC_STAT] = {uuid16(0xFF04), 	nfc_stat, 	STAT_LEN, 	20, 		0x0000,	GATTS_PERM_READ,}
	// clang-format on
};

struct gatts_service service = { .uuid = uuid16(0x00FF),
				 .char_num = 4,
				 .characteristics = chars };

void read_callback(const struct gatts_uuid *uuid, uint8_t *send_data,
		   uint16_t *len);
void write_callback(const struct gatts_uuid *uuid, const uint8_t *recv_data,
		    uint16_t len);

struct gatts_profile profile[] = { { .dev_name = "esp_test",
				     .service_num = 1,
				     .services = &service,
				     .read_cb = read_callback,
				     .write_cb = write_callback } };

inline bool get_nfc_suspended(const uint8_t nfc_conf[CONF_LEN])
{
	// 0x10 => 0001 0000
	if (nfc_conf[0] & 0x10)
		return true;
	return false;
}

inline bool get_nfc_enabled(const uint8_t nfc_conf[CONF_LEN])
{
	// 0x80 => 1000 0000
	if (nfc_conf[0] & 0x80)
		return true;
	return false;
}

inline uint8_t get_nfc_mode(const uint8_t nfc_conf[CONF_LEN])
{
	return (nfc_conf[0] & 0x60) >> 5;
}

inline void set_nfc_suspend(uint8_t nfc_conf[CONF_LEN])
{
	// 0x10 => 0001 0000
	nfc_conf[0] |= 0x10;
}

inline void set_nfc_active(uint8_t nfc_conf[CONF_LEN])
{
	// 0xEF => 1110 1111
	nfc_conf[0] &= 0xEF;
}

inline void set_nfc_enable(uint8_t nfc_conf[CONF_LEN])
{
	// 0x80 => 1000 0000
	nfc_conf[0] |= 0x80;
}

inline void set_nfc_disable(uint8_t nfc_conf[CONF_LEN])
{
	// 0x7F => 0111 1111
	nfc_conf[0] &= 0x7F;
}

inline void set_nfc_scan_mode(uint8_t nfc_conf[CONF_LEN])
{
	// 0x9F => 1001 1111
	nfc_conf[0] &= 0x9F;
}

inline void set_nfc_read_mode(uint8_t nfc_conf[CONF_LEN])
{
	// 0x40 => 0100 0000
	nfc_conf[0] |= 0x40;

	// 0xDF => 1101 1111
	nfc_conf[0] &= 0xDF;
}

inline void set_nfc_write_mode(uint8_t nfc_conf[CONF_LEN])
{
	// 0xBF => 1011 1111
	nfc_conf[0] &= 0xBF;

	// 0x20 => 0010 0000
	nfc_conf[0] |= 0x20;
}

void read_callback(const struct gatts_uuid *uuid, uint8_t *send_data,
		   uint16_t *len)
{
	gatts_err_t ret;
	printf("read event\n");

	// 如果要修改发送的value值，使用以下方法
	// ret = gatts_set_value(uuid,value,len);

	ret = gatts_get_value(uuid, send_data, len, 600);

	return;
}

// enum { EN_SCAN = 0x80, EN_READ = 0xC0, EN_WRITE = 0xA0, UN_NFC = 0x00 };
// static const uint8_t nfc_conf_cmd[] = { EN_SCAN, EN_READ, EN_WRITE, UN_NFC };

typedef enum {
	// clang-format off
	SET_ENABLE 	= 0xF0, // 使能设备
	SET_DISABLE 	= 0xF1, // 禁用设备
	SET_SCAN_MODE 	= 0xE0, // 切换为扫描模式
	SET_READ_MODE 	= 0xE1, // 切换为读模式
	SET_WRITE_MODE 	= 0xE2, // 切换为写模式
	SET_ACTIVE 	= 0x01, // 进入活动状态，进行读取或写入或扫描
	SET_SUSPEND 	= 0x02, // 进入挂起状态 suspend
	// clang-format on
} nfc_cmd_t;

struct nfc_cmd_map {
	nfc_cmd_t cmd;
	void (*func)(uint8_t nfc_conf[CONF_LEN]);
};

struct nfc_cmd_map nfc_cmd_maps[] = {
	// clang-format off
	/*cmd			func*/
	{ SET_ENABLE,		set_nfc_enable },
	{ SET_DISABLE,		set_nfc_disable },
	{ SET_SCAN_MODE,	set_nfc_scan_mode },
	{ SET_READ_MODE,	set_nfc_read_mode },
	{ SET_WRITE_MODE,	set_nfc_write_mode },
	{ SET_ACTIVE,		set_nfc_active },
	{ SET_SUSPEND,		set_nfc_suspend },
	// clang-format on
};

void write_callback(const struct gatts_uuid *uuid, const uint8_t *recv_data,
		    uint16_t len)
{
	static uint8_t nfc_conf[CONF_LEN] = { 0 };
	static uint8_t nfc_data[DATA_LEN] = { 0 };
	gatts_err_t ret;

	if (!(equal_uuid(uuid, &chars[NFC_CONF].uuid)))
		return;

	ret = gatts_get_value(uuid, nfc_conf, NULL, CONF_LEN);

	if (len == 1)
		goto len1;
	else if (len == 14)
		goto len14;
	else if (len == 16)
		goto len16;
	else
		return;

len1:
	for (int i = 0; i < LEN(nfc_cmd_maps); i++) {
		if (recv_data[0] != nfc_cmd_maps[i].cmd)
			continue;
		printf("recv cmd(1): %X\n", recv_data[0]);
		nfc_cmd_maps[i].func(nfc_conf);
		break;
	}

	ret = gatts_set_value(uuid, nfc_conf, CONF_LEN);
	return;
len14:
	printf("recv cmd(14): set conf\n");
	ret = gatts_set_value(uuid, recv_data, CONF_LEN);
	return;

len16:
	if (get_nfc_mode(nfc_conf) != 1)
		return;
	if (!get_nfc_suspended(nfc_conf))
		return;

	printf("recv cmd(16): write data\n");

	ret = gatts_set_value(&chars[NFC_DATA].uuid, recv_data, DATA_LEN);

	set_nfc_active(nfc_conf);

	ret = gatts_set_value(uuid, nfc_conf, CONF_LEN);

	return;
}

void app_main(void)
{
	esp_err_t ret;
	/* Initialize NVS. */
	ret = nvs_flash_init();
	if (ret == ESP_ERR_NVS_NO_FREE_PAGES ||
	    ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
		ESP_ERROR_CHECK(nvs_flash_erase());
		ret = nvs_flash_init();
	}
	ESP_ERROR_CHECK(ret);

	gatts_init(&profile[0]);

	rc522_init();

	/*-------------------------- 创建线程 ---------------------------*/
	xTaskCreate(rc522_task, "rc522_task", 4096, NULL, 0, NULL);
	// xTaskCreatePinnedToCore(rc522_task, "rc522_task", 4096, NULL, 0, NULL,0);
}
